﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.ExportToRTR.CApExportToRTRExportManager
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using EngineeringInternalExtension;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Tecnomatix.Engineering;
using Tecnomatix.Planning;


namespace DnProcessSimulateCommands.ExportToRTR{

/// <summary>
/// 导出调度器：
/// - 对输入对象进行分类/抽取（机器人、设备、静态体、导轨）
/// - 维护“对象→机器人”的附着/挂载/导轨关系
/// - 统一触发各导出器将 CAD 与 YAML 对象写入工程目录
/// </summary>
public class CApExportToRTRExportManager
{
  private TxObjectList m_objects;
  private Dictionary<ITxObject, ITxLocatableObject> m_objToDelegatedAttachmentPredecessor = new Dictionary<ITxObject, ITxLocatableObject>();
  public static int LOD_VALUE = 1;
  public static bool UseWorkingFrame = true;

  internal CApExportToRTRRobotsExporter Robots { get; }

  internal CApExportToRTRDevicesExporter Devices { get; }

  internal CApExportToRTRStaticExporter Statics { get; }

  internal CApExportToRTRRailsExporter Rails { get; }

  internal Dictionary<ITxObject, TxRobot> RobotChildrenWith3D => this.Robots.ChildernWith3DOfRobot;

  internal Dictionary<ITxObject, TxRobot> RobotSuplementsWith3D => this.Robots.ObjectsWith3DOfRobot;

  internal HashSet<ITxObject> StaticObjectsWith3D
  {
    get
    {
      HashSet<ITxObject> staticObjectsWith3D = new HashSet<ITxObject>((IEnumerable<ITxObject>) this.Statics.Exported3D);
      staticObjectsWith3D.UnionWith((IEnumerable<ITxObject>) this.Devices.Exported3D);
      return staticObjectsWith3D;
    }
  }

  internal Dictionary<TxRobot, Dictionary<string, ITxObject>> RobotPrototypeLinksWith3D
  {
    get => this.Robots.RobotToProtoLinks;
  }

  /// <summary>
  /// 构造并初始化四类导出器（机器人/设备/静态/导轨）。
  /// </summary>
  public CApExportToRTRExportManager(
    TxObjectList objects,
    CUiExportToRTRContentDataHandler dataHandler,
    TxReportWriterEx logWriter)
  {
    this.m_objects = objects;
    this.Robots = new CApExportToRTRRobotsExporter(dataHandler, logWriter);
    this.Devices = new CApExportToRTRDevicesExporter();
    this.Statics = new CApExportToRTRStaticExporter();
    this.Rails = new CApExportToRTRRailsExporter();
  }

  /// <summary>
  /// 执行导出：
  /// 1) 清空 CAD 原型缓存（避免重复写文件）
  /// 2) 对对象分类
  /// 3) 依次导出导轨/机器人/设备/静态体
  /// </summary>
  public void Export(CApExportToRTRXmlWriter writer, string path, string worldLink)
  {
    CApExportToRTRSTLWriter.Prototypes.Clear();
    this.SortObjects();
    this.Rails.Export(writer, path, worldLink);
    this.Robots.Export(writer, path, worldLink);
    this.Devices.Export(writer, path, worldLink);
    this.Statics.Export(writer, path, worldLink);
  }

  /// <summary>
  /// 对输入的对象列表做一次全面分类：
  /// - 遇到集合则递归遍历
  /// - 具备可见且有近似体的对象会进入相应导出器
  /// - 同时抽取挂载、导轨与附着关系
  /// </summary>
  private void SortObjects()
  {
    foreach (ITxObject itxObject in (Collection<ITxObject>) this.m_objects)
      this.SortObject(itxObject);
    this.ExtractRobotMountedObjects();
    this.ExtractRails();
    this.ExtractRobotAttachedObjects();
  }

  /// <summary>
  /// 分类一个对象：
  /// - 机器人（≥4 驱动关节）→ Robots
  /// - 设备 → Devices
  /// - 几何/组件 → Statics（并记录可能的附着父）
  /// - 集合：递归其子
  /// 仅处理“可见且有近似体”的可显示对象。
  /// </summary>
  private void SortObject(ITxObject obj, ITxLocatableObject attachmentPredecessor = null)
  {
    if (!CApExportToRTRUtils.IsVisibleAndHaveApprox(obj as ITxDisplayableObject))
      return;
    ITxPlanningObject itxPlanningObject;
    switch (obj)
    {
      case ITxObjectCollection collection when this.ContainsRobot(collection):
        this.SortChildren(collection);
        return;
      case TxRobot txRobot when ((Collection<ITxObject>) txRobot.DrivingJoints).Count >= 4:
        this.Robots.Add(txRobot);
        return;
      case ITxDevice itxDevice:
        this.Devices.Add(itxDevice);
        return;
      case ITxComponent _:
      case ITxGeometry _:
label_8:
        this.Statics.Add(obj);
        if (attachmentPredecessor == null)
          return;
        this.m_objToDelegatedAttachmentPredecessor.Add(obj, attachmentPredecessor);
        return;
      case TxPartAppearance txPartAppearance:
        itxPlanningObject = txPartAppearance.OriginPart;
        break;
      default:
        itxPlanningObject = (ITxPlanningObject) null;
        break;
    }
    if (!(itxPlanningObject is TxPlanningPartInstance))
    {
      if (!(obj is ITxObjectCollection))
        return;
      ITxLocatableObject itxLocatableObject1 = (obj is ITxLocatableObject itxLocatableObject2 ? itxLocatableObject2.AttachmentParent : (ITxLocatableObject) null) ?? (ITxLocatableObject) null;
      if (itxLocatableObject1 != null && itxLocatableObject1 != TxApplication.ActiveDocument.PhysicalRoot)
        attachmentPredecessor = itxLocatableObject1;
      this.SortChildren(obj as ITxObjectCollection, attachmentPredecessor);
    }
    else
      goto label_8;
  }

  /// <summary>
  /// 遍历集合的直接子对象（受 ObjectsValidator.Filter 过滤），并继续分类。
  /// </summary>
  private void SortChildren(ITxObjectCollection collection, ITxLocatableObject attachmentParent = null)
  {
    foreach (ITxObject directDescendant in (Collection<ITxObject>) collection.GetDirectDescendants((ITxTypeFilter) CApExportToRTRObjectsValidator.Filter))
      this.SortObject(directDescendant, attachmentParent);
  }

  /// <summary>
  /// 判断集合是否包含机器人。
  /// </summary>
  private bool ContainsRobot(ITxObjectCollection collection)
  {
    return ((Collection<ITxObject>) collection.GetAllDescendants((ITxTypeFilter) new TxTypeFilter(typeof (ITxRobot)))).Count > 0;
  }

  /// <summary>
  /// 从静态/设备集中抽取出被机器人“挂载”的对象（工具/设备），
  /// 将其标记到机器人导出器并从原集合移除，避免重复导出。
  /// </summary>
  private void ExtractRobotMountedObjects()
  {
    foreach (TxRobot robot in this.Robots.Objects)
    {
      foreach (ITxObject mountedTool in (Collection<ITxObject>) robot.MountedTools)
      {
        if (this.Statics.Contains(mountedTool))
        {
          this.Robots.AddMountedObject(robot, mountedTool);
          this.Statics.Remove(mountedTool);
        }
        else if (mountedTool is ITxDevice device && this.Devices.Contains(device))
        {
          this.Robots.AddMountedDevice(robot, device);
          this.Devices.Remove(device);
        }
      }
    }
  }

  /// <summary>
  /// 收集与机器人“附着”关系的对象树（通过各级 Frame/Link 追溯），并登记：
  /// - RobotAttachedObjects / RobotAttachedDevices
  /// - 记录从 Statics/Devices 中被吸附走的对象，避免重复导出
  /// - Rail 外部轴驱动的附着对象也纳入统计
  /// </summary>
  private void ExtractRobotAttachedObjects()
  {
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> dictionary1 = this.AllRobotsAttachments<ITxObject>(this.Statics.Objects);
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> dictionary2 = this.AllRobotsAttachments<ITxDevice>(this.Devices.Objects);
    foreach (TxRobot txRobot in this.Robots.Objects)
    {
      TxRobot robot = txRobot;
      Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> dictionary3 = new Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>();
      Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> dictionary4 = new Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>();
      foreach (ITxLocatableObject directDescendant in (Collection<ITxObject>) robot.GetDirectDescendants((ITxTypeFilter) new TxTypeFilter(typeof (TxFrame))))
      {
        this.AddAttachments(dictionary1, dictionary3, directDescendant);
        this.AddAttachments(dictionary2, dictionary4, directDescendant);
      }
      foreach (ITxObject link in (Collection<ITxObject>) robot.Links)
      {
        if (link is ITxLocatableObject parent)
        {
          this.AddAttachments(dictionary1, dictionary3, parent);
          this.AddAttachments(dictionary2, dictionary4, parent);
        }
      }
      HashSet<ITxObject> hashSet = ((IEnumerable<ITxObject>) robot.MountedTools).ToHashSet<ITxObject>();
      foreach (ITxObject externalAx in (Collection<ITxObject>) robot.ExternalAxes)
      {
        if ((externalAx as TxJoint).Device is ITxTool)
          hashSet.Add((ITxObject) (externalAx as TxJoint).Device);
      }
      foreach (ITxObject itxObject in hashSet)
      {
        if (itxObject is ITxLocatableObject parent)
        {
          this.AddAttachments(dictionary1, dictionary3, parent);
          this.AddAttachments(dictionary2, dictionary4, parent);
        }
      }
      this.Robots.SetRobotAttachedObjects(robot, dictionary3);
      this.Robots.SetRobotAttachedDevices(robot, dictionary4);
      ITxDevice rail = this.Robots.GetRail(robot);
      if (rail != null)
      {
        Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> robotAttachments = new Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>();
        HashSet<ITxLocatableObject> attachedObjects = new HashSet<ITxLocatableObject>();
        foreach (ITxObject itxObject in ((IEnumerable<ITxObject>) rail.DrivingJoints).Where<ITxObject>((Func<ITxObject, bool>) (x => ((Collection<ITxObject>) robot.ExternalAxes).Contains(x))))
        {
          TxKinematicLink childLink = (itxObject as TxJoint).ChildLink;
          this.AddAttachment(dictionary1, robotAttachments, (ITxLocatableObject) childLink);
          this.AddAttachment(dictionary2, robotAttachments, (ITxLocatableObject) childLink);
        }
        foreach (KeyValuePair<ITxLocatableObject, HashSet<ITxLocatableObject>> keyValuePair in robotAttachments)
          attachedObjects.UnionWith((IEnumerable<ITxLocatableObject>) keyValuePair.Value);
        this.Robots.SetRailAttachedObjects(robot, attachedObjects);
      }
    }
  }

  /// <summary>
  /// 将一组对象中“可附着”的对象按其 AttachParent 聚合成映射表。
  /// </summary>
  private Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> AllRobotsAttachments<T>(
    HashSet<T> objects)
  {
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachments = new Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>();
    foreach (T obj in objects)
    {
      if (obj is ITxLocatableObject attachableObject)
        this.AddAttachedObject(attachableObject, attachments);
    }
    return attachments;
  }

  /// <summary>
  /// 将一个可附着对象添加到其父-子映射中（跳过 PhysicalRoot）。
  /// </summary>
  private void AddAttachedObject(
    ITxLocatableObject attachableObject,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachments)
  {
    ITxLocatableObject attachmentParent = attachableObject.AttachmentParent;
    if (attachmentParent == null || attachmentParent == TxApplication.ActiveDocument.PhysicalRoot)
      this.m_objToDelegatedAttachmentPredecessor.TryGetValue((ITxObject) attachableObject, out attachmentParent);
    if (attachmentParent == null || attachmentParent == TxApplication.ActiveDocument.PhysicalRoot)
      return;
    if (!attachments.ContainsKey(attachmentParent))
      attachments[attachmentParent] = new HashSet<ITxLocatableObject>();
    attachments[attachmentParent].Add(attachableObject);
  }

  /// <summary>
  /// 将指定父对象以及其子孙中可附着对象，加入“机器人-附着对象”映射。
  /// </summary>
  private void AddAttachments(
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachments,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> robotAttachments,
    ITxLocatableObject parent)
  {
    this.AddAttachment(attachments, robotAttachments, parent);
    if (!(parent is ITxObjectCollection objectCollection))
      return;
    foreach (ITxLocatableObject allDescendant in (Collection<ITxObject>) objectCollection.GetAllDescendants((ITxTypeFilter) new TxTypeFilter(typeof (ITxLocatableObject))))
      this.AddAttachment(attachments, robotAttachments, allDescendant, parent);
  }

  /// <summary>
  /// 添加一个父-子附着关系到映射。
  /// </summary>
  private void AddAttachment(
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> allAttachments,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> robotAttachments,
    ITxLocatableObject parent)
  {
    this.AddAttachment(allAttachments, robotAttachments, parent, parent);
  }

  /// <summary>
  /// 将某父（parent）下的全部附着对象并入指定 key 的聚合中，
  /// 同时从 Statics/Devices 中移除以避免重复导出，并递归向下展开。
  /// </summary>
  private void AddAttachment(
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> allAttachments,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> robotAttachments,
    ITxLocatableObject parent,
    ITxLocatableObject key)
  {
    if (!allAttachments.ContainsKey(parent))
      return;
    foreach (ITxLocatableObject parent1 in allAttachments[parent])
    {
      if (key is TxFrame && ((ITxObject) key).Collection is TxRobot)
        key = ((ITxObject) key).Collection as ITxLocatableObject;
      if (!robotAttachments.ContainsKey(key))
        robotAttachments[key] = new HashSet<ITxLocatableObject>();
      robotAttachments[key].Add(parent1);
      if (this.Statics.Objects.Contains((ITxObject) parent1))
        this.Statics.Objects.Remove((ITxObject) parent1);
      else if (parent1 is ITxDevice itxDevice && this.Devices.Objects.Contains(itxDevice))
        this.Devices.Objects.Remove(itxDevice);
      this.AddAttachment(allAttachments, robotAttachments, parent1);
    }
  }

  /// <summary>
  /// 从机器人的外部轴中识别“导轨”设备：
  /// - 若某外部轴对应关节属于导轨 → 标记到 Robots/Rails 映射
  /// - 并从 Devices 集合移除该导轨设备
  /// </summary>
  private void ExtractRails()
  {
    foreach (TxRobot robot in this.Robots.Objects)
    {
      foreach (ITxObject externalAx in (Collection<ITxObject>) robot.ExternalAxes)
      {
        if (CApExportToRTRUtils.IsJointOfRail((ITxRobot) robot, externalAx as TxJoint))
        {
          ITxDevice device = (externalAx as TxJoint).Device;
          this.Robots.AddRail(robot, device);
          this.Rails.Add(device, robot);
          this.Devices.Remove(device);
        }
      }
    }
  }
}
